﻿using System;
using SCG.SolarVengeanceEngine;
using System.Collections.Generic;
using SCG.General;

namespace SCG.SolarVengeance.Scenarios
{
    public class WarShipAcademy : Scenario
    {
        //cosntructor
        public WarShipAcademy()
        {
            _impulses = CreateParameter("Impulses in Game", 1000, 200, 50000);
            _powerPodCounter = Random(15, 35);
        }

        //Don't bother to assign capital
        public override bool AssignCapitals
        {
            get
            {
                return false;
            }
        }

        public override bool UsesCapitals
        {
            get
            {
                return false;
            }
        }

        //smaller map
        public override int MapWidth
        {
            get
            {
                return 75;
            }
        }
        public override int MapHeight
        {
            get
            {
                return 75;
            }
        }

        //Max 4 players
        public override int MaxPlayers
        {
            get
            {
                return 4;
            }
        }

        //Multiplayer
        public override PlayModeRecommendation Recommendation
        {
            get
            {
                return PlayModeRecommendation.MultiPlayer;
            }
        }

        //Build the scenario
        public override void BuildScenario(int numPlayers, int capitalValues, int startingResources)
        {
            //determine the number of ships in each class
            SCGPoint pt;
            int num20 = 1;
            int num10 = Random(1, 2);
            int num8 = num10 + Random(1, 2);
            int num5 = num8 + Random(1, 2);
            int num3 = num5 + Random(1, 2);                             

            //Create a fleet for each player
            _start.Clear();
            foreach (Player p in Game.Players)
            {
                //determine center of fleet, not too close to another player's
                int x = 0;
                int y = 0;
                do
                {
                    x = Random(5, 70);
                    y = Random(5, 70);
                }
                while (!LocationOK(x, y, 20));
                _start.Add(new SCGPoint(x, y));

                //build fleet - start with BIG ship
                BuildWarShipLine(num20, 20, p, x, y);
                BuildWarShipLine(num10, 10, p, x, y);
                BuildWarShipLine(num8, 8, p, x, y);
                BuildWarShipLine(num5, 5, p, x, y);
                BuildWarShipLine(num3, 3, p, x, y);            

                //Build the ScanShip
                pt = GetShipLocation(x, y);
                CreateStarShip((int)pt.X, (int)pt.Y, p, StarShipType.ScanShip, 20, 80, false);
            }

            //Create Pulsars
            for (int n = 0; n < numPlayers + 1; n++)
                CreatePulsar(Random(5, 70), Random(5, 95));

            //Create WormHoles
            for (int n = 0; n < numPlayers + 1; n++)
                CreateWormhole(Random(5, 70), Random(5, 70), Random(10, 65), Random(10, 65));
        }

        //description
        public override string Description
        {
            get
            {
                return "The best WarShip Captains undergo training at the neutral WarShip Academy, where they learn the fine art of WarShip to WarShip battle. " + Environment.NewLine + Environment.NewLine +
                    "Each player has a fleet composed of WarShips of varying Weapons ratings, and a single long range ScanShip.  Command your WarShips carefully to eliminate as many enemy ships as possible." + Environment.NewLine + Environment.NewLine +
                    "Power Pods appear on the map, and are spawned as the game progresses.  Blue Pods increase a WarShip's Engines or Weapons by 1.  Yellow Pods spawn a new Drone, and Red Pods a new WarShip." + Environment.NewLine + Environment.NewLine +                    
                    "The game ends after a fixed number of impulses (default 1,000) and the player with the most StarShips remaining wins, or if you eliminate all enemy StarShips.";
            }
        }

        //Victory conditions
        public override bool VictoryReached()
        {                    
            if (Game.Impulse == _impulses.Value)
            {
                //determine victors
                int maxShips = 0;
                foreach (Player p in Game.Players)
                    if (p.StarShips.Count > maxShips)
                        maxShips = p.StarShips.Count;
                foreach (Player p in Game.Players)
                    if (p.StarShips.Count == maxShips)
                        p.Victor = true;
                return true;
            }

            //also end if only 1 player has ships standing
            int playersWithShips = 0;
            foreach (Player p in Game.Players)
                if (p.StarShips.Count > 0)
                    playersWithShips++;

            if (playersWithShips < 2)
            {
                foreach (Player p in Game.Players)
                    if (p.StarShips.Count > 0)
                        p.Victor = true;
                return true;
            }

            return false;
        }

        //Create power pods every 20 to 40 impulses
        public override void ProcessImpulse(int impulse)
        {
            //spawn initial pods
            if (impulse == 1)
            {
                _initialPods = true;
                _variance = 10;
                do
                {
                    _podX = Random(0, 74);
                    _podY = Random(0, 74);
                }
                while (!PodLocationOK(_podX, _podY));
                SetValue("PodX", _podX.ToString());
                SetValue("PodY", _podY.ToString());

                for (int n = 0; n < 12; n++)
                    SpawnPod();

                _initialPods = false;
            }

            //spawn pod every 20 to 40 impulses
            _powerPodCounter--;
            if (_powerPodCounter <= 0)
            {
                //reset counter
                _powerPodCounter = Random(15, 35);

                //Determine type of pod to spawn
                SpawnPod();
            }

            //Process StarShips over Power Pods
            for (int n = Game.UDOs.Count - 1; n >= 0; n--)
            {
                UDO pod = Game.UDOs[n];
                if (pod.Carrier != null)
                {
                    StarShip ship = pod.Carrier;

                    //process the effect of the pos
                    switch (pod.Name)
                    {
                        case "Blue Pod":
                            if (pod.Carrier.ShipType == StarShipType.WarShip)
                            {                                
                                if (pod.Carrier.MaxEngines == 20 || Random(1, 100) < 50)
                                    DynamicEvents.AdjustShipValues(ship, ship.Engines, ship.MaxEngines, ship.Value + 1, ship.MaxValue + 1, true);
                                else
                                    DynamicEvents.AdjustShipValues(ship, ship.Engines + 1, ship.MaxEngines + 1, ship.Value, ship.MaxValue, true);                              
                            }
                            break;
                        case "Yellow Pod":
                            DynamicEvents.CreateStarShip(ship.X, ship.Y, ship.Owner, StarShipType.Drone, 20, 0, false);
                            break;
                        case "Red Pod":
                            DynamicEvents.CreateStarShip(ship.X, ship.Y, ship.Owner, StarShipType.WarShip, Random(10, 20), Random(1, 10), false);
                            break;
                    }

                    //remove the pod from play
                    DynamicEvents.RemoveObject(pod);
                }
            }
        }

        //communicate pod spawn location
        public override void ClientProcessImpulse(int impulse)
        {
            if (GetValue("PodX") != "")
            {
                _podX = Int32.Parse(GetValue("PodX"));
                _podY = Int32.Parse(GetValue("PodY"));
            }
        }

        //private members
        ScenarioParameter _impulses = null;
        private List<SCGPoint> _start = new List<SCGPoint>();
        private int _powerPodCounter;
        private int _podX;
        private int _podY;
        private double _variance = 30;
        private bool _initialPods = true;

        //Spawn a pod
        private void SpawnPod()
        {
            string podName;
            string podImage;
            string podDesc;
            if (Random(1, 100) < 45)
            {
                if (Random(1, 100) < 40)
                {
                    podName = "Red Pod";
                    podImage = "RedPod";
                    podDesc = "Move a StarShip over this Pod to spawn a new WarShip.";
                }
                else
                {
                    podName = "Yellow Pod";
                    podImage = "YellowPod";
                    podDesc = "Move a StarShip over this Pos to spawn a new Drone.";
                }
            }
            else
            {
                podName = "Blue Pod";
                podImage = "BluePod";
                podDesc = "Move a WarShip over this Pod and its Weapons or Engines will be raised by 1 point.";
            }

            //create the Pod
            DynamicEvents.CreateUDO(_podX, _podY, podName, podImage, podDesc, true, true, false);

            //Change location of next pod spawn
            if (!_initialPods && Random(1, 100) < 7)
            {
                _podX = Random(0, 74);
                _podY = Random(0, 74);
            }
            else
            {
                SCGPoint next = GetShipLocation(_podX, _podY);
                _podX = (int)next.X;
                _podY = (int)next.Y;
            }
            SetValue("PodX", _podX.ToString());
            SetValue("PodY", _podY.ToString());
        }

        //Is the specified location OK for a fleet?
        private bool LocationOK(int x, int y, int distance)
        {
            foreach (SCGPoint pt in _start)
                if (Distance(x, y, pt.X, pt.Y) < distance)
                    return false;
            return true;
        }

        //Is the pod location OK?  Distance between all players should not exceed 30
        private bool PodLocationOK(int x, int y)
        {
            _variance += 0.05d;
            double max = Double.MinValue;
            double min = Double.MaxValue;
            foreach (SCGPoint pt in _start)
            {
                double distance = Distance(x, y, pt.X, pt.Y);
                if (distance > max)
                    max = distance;
                if (distance < min)
                    min = distance;
            }
            return (max - min) < _variance;
        }

        //get a location for a StarShip
        private SCGPoint GetShipLocation(int x, int y)
        {
            int shipX = 0;
            int shipY = 0;
            do
            {
                shipX = Random(5, 70);
                shipY = Random(5, 70);
            }
            while(Distance(x, y, shipX, shipY ) > 7);
            return new SCGPoint(shipX, shipY);
        }

        //Build a class of WarShip
        private void BuildWarShipLine(int numShips, int weapons, Player p, int x, int y)
        {
            while (numShips > 0)
            {
                SCGPoint pt = GetShipLocation(x, y);
                CreateStarShip((int)pt.X, (int)pt.Y, p, StarShipType.WarShip, 12, weapons, false);
                numShips--;
            }
        }
    }
}
